#include "NetworkedActor.h"
#include "BPhysicsActor.h"
#include "GMActorChanges.h"
#include "Server.h"
#include "Client.h"
#include "Engine.h"

int NetworkedActor::ACTOR_ID_GENERATOR = 0;

NetworkedActor::NetworkedActor(bool genID) : 
m_actor(NULL),
m_networkID(-1),
m_active(true),
m_recievedServerUpdate(false),
m_serverUpdateCounter(0)
{
	if(genID)
		m_networkID = GenerateNewID();

	memset(m_curRot, 0, sizeof(float)*4);
	m_curRot[3] = 1.0f;
	memset(m_curPos, 0, sizeof(float)*3);
	memset(m_curLVel, 0, sizeof(float)*3);
	memset(m_curAVel, 0, sizeof(float)*3);

	memset(m_newServerRot, 0, sizeof(float)*4);
	m_newServerRot[3] = 1.0f;
	memset(m_newServerPos, 0, sizeof(float)*3);
	memset(m_newServerLVel, 0, sizeof(float)*3);
	memset(m_newServerAVel, 0, sizeof(float)*3);
}

void NetworkedActor::SendToClients()
{
    GMActorChanges gmac;
    gmac.SetNetworkID(m_networkID);
	memcpy(gmac.m_rotation, m_curRot, sizeof(float)*4);
	memcpy(gmac.m_translation, m_curPos, sizeof(float) * 3);
	memcpy(gmac.m_linearVelocity, m_curLVel, sizeof(float) * 3);
	memcpy(gmac.m_angluarVelocity, m_curAVel, sizeof(float) * 3);

    TheServer::Instance()->SendToAllClients(gmac);
}

void NetworkedActor::UpdateToServer( GMActorChanges& gmac )
{
	m_recievedServerUpdate = true;
	memcpy(m_newServerRot, gmac.m_rotation, sizeof(float)*4);
	memcpy(m_newServerPos, gmac.m_translation, sizeof(float) * 3);
	memcpy(m_newServerLVel, gmac.m_linearVelocity, sizeof(float) * 3);
	memcpy(m_newServerAVel, gmac.m_angluarVelocity, sizeof(float) * 3);
}

void NetworkedActor::Update(bool server)
{
    m_active = m_actor->IsAwake();
	if(!m_active)
		return;

	//Update current Data
	btQuaternion& rot = m_actor->GetBodyPointer()->getCenterOfMassTransform().getRotation();
	const btVector3& pos = m_actor->GetBodyPointer()->getCenterOfMassTransform().getOrigin();
	const btVector3& lVel = m_actor->GetBodyPointer()->getLinearVelocity();
	const btVector3& aVel = m_actor->GetBodyPointer()->getAngularVelocity();
	memcpy(m_curRot, rot, sizeof(float)*4);
	memcpy(m_curPos, pos, sizeof(float) * 3);
	memcpy(m_curLVel, lVel, sizeof(float) * 3);
	memcpy(m_curAVel, aVel, sizeof(float) * 3);

	if(server) //Server update is finished
		return;


	if(!m_recievedServerUpdate) //if we haven't received an update recently, don't bother lerping
		return;

	m_serverUpdateCounter++;
	if(m_serverUpdateCounter > 4)
		m_recievedServerUpdate = false;		//if this is the fourth time using this data, stop using it


	//now clients need to lerp over to the new server data
	int lag = TheClient::Instance()->GetLagTime();
	if(lag < 10 || lag > 500)
		lag = 55;				//Decent amount
	//55 / 16ms = 3.something
	float frames = (float)lag / 1000.0f * (1.0f / (float)Engine::Instance()->m_frameDisplay);
	//we are frames number of Frames behind the server
	float lerpTime = 1.0f / frames;
	
	int numberOfFloats[4] = {4,3,3,3};
	float* dataStart[4] =    {m_curRot, m_curPos, m_curLVel, m_curAVel};
	float* dataFinish[4] = {m_newServerRot, m_newServerPos, m_newServerLVel, m_newServerAVel};
	for(int i = 0; i < 4; ++i)
		for(int j = 0; j < numberOfFloats[i]; ++j)
			dataStart[i][j] = Vector::lerp(dataStart[i][j], dataFinish[i][j], lerpTime);

	btQuaternion q(m_curRot[0],m_curRot[1],m_curRot[2],m_curRot[3]);
	q.normalize();
	btVector3 tr(m_curPos[0],m_curPos[1],m_curPos[2]);
	btVector3 lv(m_curLVel[0],m_curLVel[1],m_curLVel[2]);
	btVector3 av(m_curAVel[0],m_curAVel[1],m_curAVel[2]);
	m_actor->GetBodyPointer()->setCenterOfMassTransform(btTransform(q, tr));
	m_actor->GetBodyPointer()->setLinearVelocity(lv);
	m_actor->GetBodyPointer()->setAngularVelocity(av);
}

bool NetworkedActor::HasChanged()
{
	return true;
}
